//#define __FORCE_TRACE__
//#define __FORCE_DEBUG__
//#define __FORCE_INFO__
#define THIS_FILE "ia\fn_stuckGroup.sqf"
#include <tmf_constants.h>
#include <tmf_macros.h>

TMFPROFILERSTART;

/*
	OPTIONS
	-------
	killed : the group will start moving when more than 2 members died already
	hit : unlock the unit when it has taken a hit
	fire : unlock the unit when it has fired more than 2 times
	firednear : unlock the unit when an enemy has fired less than X meters away

*/
TRACE_1("Start",_this);
private ["_obj","_grp","_positions","_options"];
DEFAULT_PARAM(_obj,0,objNull);
DEFAULT_PARAM(_positions,1,[]);
DEFAULT_PARAM(_options,2,[]);
_grp = grpNull;
if (IS_OBJECT(_obj) && {!(isNull _obj)} && {_obj isKindOf "Man"}) then {
	_grp = group _obj;
};
if (IS_GROUP(_obj) && {!(isNull _obj)}) then {
	_grp = _obj;
};

if !(isNull _grp) then {
	if (!isServer && !(local (leader _grp))) exitWith { ERROR_1("Execution should be on server or local to the unit",_this); };
	_grp setVariable ["STUCK_GROUP_COUNTER",0];
	if (IS_STRING(_options)) then {
		_grp setVariable [toUpper(_options),true];
	};
	if (IS_ARRAY(_options) && {count _options > 0}) then {
		{
			_grp setVariable [toUpper(_x), true];
		} foreach _options;
	};
	[_grp,_positions] spawn {
		private ["_grp","_positions","_unit","_pos","_corrected"];
		DEFAULT_PARAM(_grp, 0, grpNull);
		DEFAULT_PARAM(_positions, 1, []);
		if !(isNull _grp) then {
			{
				_unit = _x;
				_unit disableAI "MOVE";
				// We check if there are stuck positions left to use.
				// If not, we just add the Killed event handler if needed.
				if (count _positions > _forEachIndex) then {
					_pos = _positions select _forEachIndex;
					// Positions are either just a position, or a combination of: [pos, dir, stance]
					if (count _pos < 3 || ((count _pos >= 3) && IS_STRING((_pos select 2)))) then {
						_corrected = (_pos select 0);
						_corrected set [2, (_corrected select 2) + 0.1];
						_unit setPosATL _corrected;
						if (count _pos > 1) then { _unit setDir (_pos select 1); };
						if (count _pos > 2) then { _unit setUnitPos (_pos select 2); };
					} else {
						_corrected = _pos;
						_corrected set [2, (_corrected select 2) + 0.1];
						_unit setPosATL _corrected;
					};
				};
				// Alternative method to set position
				if (count (_unit getVariable ["POSITION",[]]) > 0) then {
					_unit setPosATL (_unit getVariable ["POSITION",(getPosATL _unit)]);
				};
				// Alternative method to set direction
				if ((_unit getVariable ["DIRECTION",-9999]) != -9999) then {
					_unit setDir (_unit getVariable ["DIRECTION",(getDir _unit)]);
				};
				// Alternative method to set stance
				if (_unit getVariable ["STANCE",""] != "") then {
					_unit setUnitPos (_unit getVariable ["STANCE","UP"]);
				};
				if ((_grp getVariable ["FIRE",false])) then {
					_unit setVariable [QGVAR(fired_evh),_unit addEventHandler ["fired",{
							// unit / weapon / muzzle / mode / ammo / magazine / projectile
							// If the unit fires more than 2 times at an enemy, we unlock it.
							(_this select 0) setVariable ["UNLOCK_FIRE_COUNT",((_this select 0) getVariable ["UNLOCK_FIRE_COUNT",0]) + 1];
							if (((_this select 0) getVariable ["UNLOCK_FIRE_COUNT",0]) >= 2) then {
								DEBUG_1("Fire unlock",_this);
								(_this select 0) enableAI "MOVE"; (_this select 0) forceSpeed 0;
								(_this select 0) removeEventHandler ["fired", (_this select 0) getVariable [QGVAR(fired_evh),-1]]; 
							};
						}]
					];
				};
				if ((_grp getVariable ["HIT",false])) then {
					_unit setVariable [QGVAR(hit_evh),_unit addEventHandler ["Hit",{
							// unit / causedBy / damage
							// If the cause is a player, unlock
							if (alive(_this select 0) && {!(isNull (_this select 1))} && {isPlayer(_this select 1)}) then {
								DEBUG_1("Hit Unlock",_this);
								(_this select 0) enableAI "MOVE"; (_this select 0) setUnitPos "AUTO"; doStop (_this select 0); (_this select 0) forceSpeed -1;
								(_this select 0) removeEventHandler ["Hit", (_this select 0) getVariable [QGVAR(hit_evh),-1]]; 
							};
						}]
					];
				};
				if ((_grp getVariable ["FIREDNEAR",false])) then {
					_unit setVariable [QGVAR(firednear_evh),_unit addEventHandler ["FiredNear",{
							// unit / firer / distance / weapon / muzzle / mode / ammo
							// Check if someone fires less than 15m away and if someone does, we check if it's an enemy, in such a case, unlock the unit
							if (((_this select 2) <= 15) && {((side (_this select 1)) getFriend (side (_this select 0)) < 0.6)}) then {
								DEBUG_1("Fired Near Unlock",_this);
								// Reveal player to unit, to make it more reactive
								(_this select 0) reveal [(_this select 1),2];
								(_this select 0) enableAI "MOVE"; (_this select 0) setUnitPos "AUTO"; doStop (_this select 0); (_this select 0) forceSpeed -1;
								(_this select 0) removeEventHandler ["FiredNear", (_this select 0) getVariable [QGVAR(firednear_evh),-1]]; 
							};
						}]
					];
				};
				if ((_grp getVariable ["KILLED",false])) then {
					_unit setVariable [QGVAR(killed_evh),_unit addEventHandler ["killed",{
							// Increment the group killed counter if the killer is a player
							if (isPlayer(_this select 1)) then {
								(group (_this select 0)) setVariable ["STUCK_GROUP_COUNTER",((group (_this select 0)) getVariable "STUCK_GROUP_COUNTER") + 1];
							};
							// If 2 units of the group or more are killed, let the group move freely.
							if (((group (_this select 0)) getVariable "STUCK_GROUP_COUNTER") >= 2) then {
								DEBUG_1("Killed unlock",_this);
								// Prevents the code below from executing again
								(group (_this select 0)) setVariable ["STUCK_GROUP_COUNTER", -1000];
								// We let units move freely and chose their stance.
								{_x enableAI "MOVE"; _x setUnitPos "AUTO"; doStop _x; (_this select 0) forceSpeed -1; } foreach (units (group (_this select 0)));
								(_this select 0) removeEventHandler ["killed", (_this select 0) getVariable [QGVAR(killed_evh),-1]]; 
							};
						}]
					];
				};
			} foreach (units _grp);
			TRACE_1("Group set up",_grp);
		};
	};
} else {
	ERROR_1("Invalid input",_this);
};

TMFPROFILERSTOP;